import { FlowInstanceInfo } from './instance';
import { FlowPreInput } from './workflow';

export enum PlayerType {
	User = 'user',
	Role = 'role',
	Organ = 'organ',
	Custom = 'custom',
}

export interface FlowPlayerInfo {
	get type(): PlayerType;
	readonly id: string;
	readonly name: string;
}

export abstract class FlowPlayer implements FlowPlayerInfo {
	abstract get type(): PlayerType;
	constructor(public id: string, public name: string) {}
	static toPlayerInfo(player: FlowPlayer): FlowPlayerInfo {
		return {
			type: player.type,
			id: player.id,
			name: player.name,
		};
	}

	static isCustomPlayer(player: FlowPlayer): player is CustomPlayer {
		return player.type === PlayerType.Custom;
	}
	static isUserPlayer(player: FlowPlayer): player is UserPlayer {
		return player.type === PlayerType.User;
	}
	static isRolePlayer(player: FlowPlayer): player is RolePlayer {
		return player.type === PlayerType.Role;
	}
	static isOrganPlayer(player: FlowPlayer): player is OrganPlayer {
		return player.type === PlayerType.Organ;
	}
}

export class UserPlayer extends FlowPlayer {
	override get type(): PlayerType.User {
		return PlayerType.User;
	}
	constructor(id: string, name: string) {
		super(id, name);
	}
}

export class RolePlayer extends FlowPlayer {
	override get type(): PlayerType.Role {
		return PlayerType.Role;
	}
	constructor(id: string, name: string) {
		super(id, name);
	}
}

export class OrganPlayer extends FlowPlayer {
	override get type(): PlayerType.Organ {
		return PlayerType.Organ;
	}
	constructor(id: string, name: string, public withSubOrgan: boolean) {
		super(id, name);
	}
}

export type Players = (UserPlayer | RolePlayer | OrganPlayer)[];

export class CustomPlayer extends FlowPlayer {
	override get type(): PlayerType.Custom {
		return PlayerType.Custom;
	}
	constructor(
		id: string,
		name: string,
		public getPlayers: (instance: FlowInstanceInfo, input: FlowPreInput) => Players | Promise<Players>,
		public isValidPlayer: (user: UserPlayer) => boolean | Promise<boolean>
	) {
		super(id, name);
	}
}
